package com.zg.datapush.service;

import com.zg.datapush.constant.DataPushConstants;
import com.zg.common.core.dao.datapush.dao.DpPushRecordDao;
import com.zg.common.core.dao.datapush.dao.DpPushTaskDao;
import com.zg.common.core.dao.datapush.entity.DpPushRecord;
import com.zg.common.core.dao.datapush.entity.DpPushTask;
import com.zg.datapush.engine.DatabasePushEngine;
import com.zg.datapush.engine.RestPushEngine;
import com.zg.datapush.handler.PushResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * 推送服务（增强版）
 * @author zg
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class PushService {

    private final DpPushTaskDao pushTaskDao;
    private final DpPushRecordDao pushRecordDao;
    private final DatabasePushEngine databasePushEngine;
    private final RestPushEngine restPushEngine;
    private final PushLogRecorder pushLogRecorder;

    /**
     * 执行推送任务（手动触发）
     */
    public void executePushTask(Long taskId) {
        executePushTaskInternal(taskId, DataPushConstants.TRIGGER_TYPE_MANUAL, null);
    }

    /**
     * 执行推送任务（定时触发 - Cron）
     */
    public void executePushTaskByCron(Long taskId) {
        executePushTaskInternal(taskId, DataPushConstants.TRIGGER_TYPE_CRON, null);
    }

    /**
     * 执行推送任务（重推）
     */
    @Async
    public void executePushTaskWithRePush(Long taskId, Long parentRecordId) {
        executePushTaskInternal(taskId, DataPushConstants.TRIGGER_TYPE_MANUAL, parentRecordId);
    }

    /**
     * 执行推送任务的内部方法
     */
    @Transactional(rollbackFor = Exception.class)
    public void executePushTaskInternal(Long taskId, String triggerType, Long parentRecordId) {
        DpPushTask task = pushTaskDao.getById(taskId);
        if (task == null) {
            log.error("推送任务不存在: {}", taskId);
            return;
        }

        if (!DataPushConstants.TASK_STATUS_ENABLED.equals(task.getStatus())) {
            log.warn("推送任务未启用: {}", taskId);
            return;
        }

        // 创建推送记录
        DpPushRecord record = createPushRecord(task, triggerType, parentRecordId);

        // 开始记录推送日志
        pushLogRecorder.startRecording(record.getId());

        try {
            log.info("开始执行推送任务: {}, 记录ID: {}", task.getTaskName(), record.getId());

            PushResult result = pushLogRecorder.executeWithLog(
                "执行推送任务",
                this.getClass().getName(),
                "executePushTaskInternal",
                task,
                () -> {
                    // 根据目标类型执行推送
                    if (DataPushConstants.TARGET_TYPE_DATABASE.equals(task.getTargetType())) {
                        return databasePushEngine.executeDatabasePush(task);
                    } else if (DataPushConstants.TARGET_TYPE_REST.equals(task.getTargetType())) {
                        return restPushEngine.executeRestPush(task);
                    } else {
                        return PushResult.failure("不支持的目标类型: " + task.getTargetType());
                    }
                }
            );

            // 设置总数量（从推送结果中获取）
            record.setTotalCount(result.getSuccessCount() + result.getFailedCount());

            // 更新推送记录
            updatePushRecord(record, result);

            // 更新任务的最后推送时间（增量推送时使用）
            if (result.isSuccess() && DataPushConstants.PUSH_MODE_INCREMENT.equals(task.getPushMode())) {
                pushLogRecorder.executeWithLog(
                    "更新最后推送时间",
                    this.getClass().getName(),
                    "updateLastPushTime",
                    task.getId(),
                    () -> {
                        task.setLastPushTime(new Date());
                        pushTaskDao.updateById(task);
                    }
                );
            }

            log.info("推送任务执行完成: {}, 状态: {}", task.getTaskName(), result.isSuccess() ? "成功" : "失败");

        } catch (Exception e) {
            log.error("推送任务执行失败: {}", taskId, e);
            record.setStatus(DataPushConstants.RECORD_STATUS_FAILED);
            record.setErrorMessage(e.getMessage());
            record.setEndTime(new Date());
            record.setDuration(record.getEndTime().getTime() - record.getStartTime().getTime());
            pushRecordDao.updateById(record);
        } finally {
            // 结束记录推送日志
            pushLogRecorder.endRecording();
        }
    }


    /**
     * 创建推送记录（增强版）
     */
    private DpPushRecord createPushRecord(DpPushTask task, String triggerType, Long parentRecordId) {
        DpPushRecord record = new DpPushRecord();
        record.setTaskId(task.getId());
        record.setTaskName(task.getTaskName());
        record.setPushMethod(task.getTargetType());
        record.setPushMode(task.getPushMode());
        record.setTriggerType(triggerType);
        record.setParentRecordId(parentRecordId);
        record.setStartTime(new Date());
        record.setStatus(DataPushConstants.RECORD_STATUS_RUNNING);
        record.setRetryCount(0);

        // 设置单据类型（直接使用源表名）
        record.setDocumentType(task.getSourceTableName());

        pushRecordDao.save(record);
        return record;
    }

    /**
     * 更新推送记录（增强版）
     */
    private void updatePushRecord(DpPushRecord record, PushResult result) {
        record.setEndTime(new Date());
        record.setDuration(record.getEndTime().getTime() - record.getStartTime().getTime());

        // 设置状态
        if (result.isSuccess()) {
            if (result.getFailedCount() > 0) {
                record.setStatus(DataPushConstants.STATUS_PARTIAL); // 部分成功
            } else {
                record.setStatus(DataPushConstants.RECORD_STATUS_SUCCESS);
            }
        } else {
            record.setStatus(DataPushConstants.RECORD_STATUS_FAILED);
        }

        record.setSuccessCount(result.getSuccessCount());
        record.setFailedCount(result.getFailedCount());

        if (!result.isSuccess()) {
            record.setErrorMessage(result.getMessage());
        }

        pushRecordDao.updateById(record);
    }



}
